package com.gzsxy.esjy.sign.socket;

import com.alibaba.fastjson.JSON;
import com.gzsxy.esjy.sign.async.AsyncWsClient;
import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 处理器
 * @author zhangxiaolong
 * @since 2022/7/15
 */
@ChannelHandler.Sharable
@Slf4j
public class WsClientMessageHandler extends SimpleChannelInboundHandler<Object> {

    private final WebSocketClientHandshaker handShaker;
    private ChannelPromise handShakeFuture;
    private final AsyncWsClient asyncWsClient;

    public WsClientMessageHandler(WebSocketClientHandshaker handShaker, AsyncWsClient asyncWsClient) {
        this.handShaker = handShaker;
        this.asyncWsClient = asyncWsClient;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //进行消息处理
        Channel channel = ctx.channel();
        // 这里是第一次使用http连接成功的时候
        if (!handShaker.isHandshakeComplete()) {
            handShaker.finishHandshake(channel, (FullHttpResponse) msg);
            log.info("WebSocket Client connected: ws客户端连接成功");
            handShakeFuture.setSuccess();
            return;
        }

        // 这里是第一次使用HTTP连接失败的时候
        if (msg instanceof FullHttpResponse) {
            FullHttpResponse response = (FullHttpResponse) msg;
            throw new IllegalStateException("Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
        }

        //响应底层心跳
        if (msg instanceof PingWebSocketFrame) {
            log.debug("接收到来自于 {} 的[{}]心跳信息 ", asyncWsClient.getIp(), ctx.channel().toString());
            ctx.writeAndFlush(new PongWebSocketFrame());
            return;
        }

        //获取客户端的响应心跳:不做任何处理
        if (msg instanceof PongWebSocketFrame) {
            log.debug("接收到来自于 {} 的[{}]心跳响应 ", asyncWsClient.getIp(), ctx.channel().toString());
            return;
        }

        if(msg instanceof CloseWebSocketFrame){
            log.error("接收到 CloseWebSocketFrame ,不支持的协议，不做任何处理,msg:【{}】", JSON.toJSONString(msg));
            return ;
        }

        if(msg instanceof BinaryWebSocketFrame){
            log.error("接收到 BinaryWebSocketFrame ,不支持的协议，不做任何处理,msg:【{}】", JSON.toJSONString(msg));
            return ;
        }

        if(msg instanceof ContinuationWebSocketFrame){
            log.error("接收到 ContinuationWebSocketFrame ,不支持的协议，不做任何处理,msg:【{}】", JSON.toJSONString(msg));
            return ;
        }

        // 处理消息
        asyncWsClient.getAsyncWsCallBack().doResponse(asyncWsClient, msg);
    }

    /**
     * Handler本身被添加到ChannelPipeline时调用
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        handShakeFuture = ctx.newPromise();
    }

    /**
     * Handler本身被从ChannelPipeline中删除时调用
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
    }

    /**
     * channel 通道 action 活跃的 当客户端主动链接服务端的链接后，这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("channelActive: 客户端连接建立");
        Channel ch = ctx.channel();
        // 在通道连接成功后发送握手连接
        handShaker.handshake(ch);
        super.channelActive(ctx);
        asyncWsClient.setChannel(ch);
        asyncWsClient.getAsyncWsCallBack().connected(asyncWsClient);
    }

    /**
     * 异常发生
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("客户端异常关闭");
        super.exceptionCaught(ctx, cause);
        ctx.close();
        asyncWsClient.getAsyncWsCallBack().exception(asyncWsClient, cause);
    }

    /**
     * channel 通道 Inactive 不活跃的 当客户端主动断开服务端的链接后，这个通道就是不活跃的。也就是说客户端与服务端关闭了通信通道并且不可以传输数据
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端连接关闭");
        super.channelInactive(ctx);
        asyncWsClient.getAsyncWsCallBack().disConnected(asyncWsClient);
    }

    /**
     * 通道 读取 完成 在通道读取完成后会在这个方法里通知，对应可以做刷新操作 ctx.flush()
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    /**
     * 定时任务
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            asyncWsClient.getAsyncWsCallBack().heartbeat(asyncWsClient, event);
        }
    }
}
